# Copyright 2001-2007 by iNeed,Inc. All Rights Reserved.
#-*- encoding:utf-8 -*-
import sys, os, time, string,re
import logging
import socket
import sock_asynchat
import sock_asyncore
import sessionPeer
from common import *
import time
import database
import json
from googlemaps import GoogleMaps

__author__  = "Number Huang<huang.bafeng@iNeed.com>"
__status__  = "developing"
__version__ = "0.1108.13.1"




class Requester(Task):
    """
        baseclass of requester. It is a task to nofity the timeout to get the response if timeout
    """

    def __init__(self,session,responseTimeout,name):
        super(Requester,self).__init__(session,name,responseTimeout)
        self.session = session
        self.cseq = self.session.cseq
        self.name = name
        self.extraInfo={CSTR2_SESSION:session}

    def handle(self,buf):
        retCode,retInfo = getTheRetInfo(buf)
        strlist = buf.splitlines()
        for line in strlist:
            line1 = line.lstrip()
            if line1.startswith("CSeq:"):
                    cseq = getCSeq(line1)
        self.session.notifyResponse(cseq,retCode,retInfo,self.extraInfo)
        

    def run(self):
        """"
        for the tiemout check, as a task in async mode
        """
        self.session.notifyResponse(self.cseq,408,"%s timeout to get the response"%self.name,self.extraInfo)

class LOGINRequester(Requester):
    """
        handle login method
    """
    def __init__(self,session,responseTimeout):
          super(LOGINRequester,self).__init__(session,responseTimeout,"LOGINRequester")                                       #this indicates the msg center


    def handle(self,buf):
        """
        handle response,call reporter to handle the result,and return nothing
        """
        #self.log.debug("handle login response")
        retCode,retInfo = getTheRetInfo(buf)
        #if isOkResponse(recCode):
        strlist = buf.splitlines()
        for line in strlist:
            line1 = line.lstrip()
            if line1.startswith("Session:"):
                    sessionID = getSession(line1)
                    self.session.setSessionID(sessionID)
            elif line1.startswith("CSeq:"):
                    cseq = getCSeq(line1)

        self.session.notifyResponse(cseq,retCode,retInfo,self.extraInfo)
        

getPortPwdPattern=re.compile(r"Authorization: port=(\w+),pwd=([_\w]+)")
def getPortNPwd(buf):
    m = getPortPwdPattern.search(buf)
    if m:
        return m.groups()
    else:
        raise Exception,"not found port/pwd"%buf

class LOGINResponser(object):
    """
        for iNeedCenter to process the login request
    """

    def __init__(self,session):
        self.session = session
        self.log     = session.log
        self.db      = database.CreateDB(session)

    def handle(self,buf):
        """
        handle request,it is must to return the buf
        TODO: it may need to create a new task to handle it if it needs a lot time.
        use case:
            1,verify the user/pwd
            2,TODO: add active user to activeUserList
        """
        valid = 0
        strlist = buf.splitlines()
        locationParams={}
        
        for line in strlist:
            line1 = line.lstrip()
            if line1.startswith("Authorization:"):
                    listenPort,pwd = getPortNPwd(line1)
                    key={"phone=":locationParams["From"]}
                    result = self.db.fetchall("user",key)
                    if result:
                        if result[0][1]==pwd:
                            valid = 1
                        else:
                            self.log.error("invalid pwd")
                    else:
                        self.log.error("invalid user")
            elif line1.startswith("CSeq:"):
                    cseqStr = line1

            elif line1.startswith("Role:"):
                    role = int(getItem(line1)[1])                   
            else:
                    parseLocationParams(locationParams,line1)

       
        if valid:
            #key={"phone":username}
            if role==EPR_DRIVER:#because we recreate the sessionPeer,so save the ip
                addr = self.session.peer.getIP()
                self.session.peer = sessionPeer.SessionDriver(self.session)
                self.session.peer.setIP(*addr)
            self.session.peer.setPhone(locationParams["From"])
            self.session.peer.setListenPort(listenPort)
            result = self.db.fetchall(locationTable[role],key)
            locationParams["status"] = ES_IDLE
            if result:
                database.updateLocation(self.db,role,locationParams)
            else:
                database.insertLocation(self.db,role,locationParams)

            buf2 = "MC2CSP/1.0 LOGIN 200 OK\r\n"
            buf2 +="Session: %d\r\n"%self.session.createSessionID()

        else:
            buf2 = "MC2CSP/1.0 LOGIN 414 invalid user/pwd\r\n"
        
          
        buf2 += getDefaultTime() + cseqStr + "\r\n"
        self.session.sendData(buf2 + TERMINATOR)



pubIdPattern = re.compile(r"PubID: (\d+)")
def getPubID(buf):
    m = pubIdPattern.search(buf)
    if m:
        return int(m.group(1))
    else:
        raise Exception,"not found PubID"

class PUBLISHRequester(Requester):
    """
        handle publish response
    """
    def __init__(self,session,responseTimeout):
                                                #this indicates the msg center
       super(PUBLISHRequester,self).__init__(session,responseTimeout,"PUBLISHRequester")

    def handle(self,buf):
        """
        handle response,call reporter to handle the result,and return nothing
        """
        #self.log.debug("handle login response")
        retCode,retInfo = getTheRetInfo(buf)

        strlist = buf.splitlines()
        for line in strlist:
            line1 = line.lstrip()
            if line1.startswith("PubID:"):
                    pubID = getPubID(line1)
            elif line1.startswith("CSeq:"):
                    cseq = getCSeq(line1)
        self.extraInfo[CSTR2_PUBID] = pubID
        self.extraInfo[CSTR2_CSEQ]  = cseq
        self.extraInfo[CSTR2_SESSION] = self.session
        self.session.notifyResponse(cseq,retCode,retInfo,self.extraInfo)
        

PublishActiveTime=1800  #@the time before the depart that the matcher works for the publish,default is 1800 seconds
class PUBLISHResponser(object):
    """
        For iNeedCenter to process the publish request
    """

    def __init__(self,session):
        self.session = session
        self.log   = session.log
        self.db    = database.CreateDB(session)
    def _calculateExecuteTime(self,departureTime,timeout):
        """
        calculate the time to match the publish,
        current is
        @TODO: divide it into 2 cases, instant and long term 
        """
        curTime = time.time()
        return curTime#departureTime-timeout-PublishActiveTime
    
    
    def _preProcess(self,serviceDict):
        """
        We will check the address to avoid the multiple address conflict,like some chain hotel.
        @ret (retCode,detailedInfo ended with \r\n)
        """
        depart = serviceDict["address"]
        dest   = serviceDict["address2"]
        return (EN_OK,"")
    def handle(self,buf):
        """
        currently, it just insert the new service to database, and
        return the pubID

        """
        strlist = buf.splitlines()
        serviceParamDict={}
        locationParams={}
        num = 0
        for line in strlist:
            num += 1
            line1 = line.lstrip()
            if line1.startswith("Service:"):
                 seriveParamList = strlist[num:]
                 parseServiceParams(serviceParamDict,seriveParamList)
                 break

            elif line1.startswith("CSeq:"):

                 cseqStr = line1

            elif line1.startswith("Session:"):

                 sessionStr = line1

            else:
                 parseLocationParams(locationParams,line1)

        serviceParamDict["phone"]   =   locationParams["From"]
        serviceParamDict["execTime"]=   self._calculateExecuteTime(serviceParamDict["departureTime"],serviceParamDict["timeout"])
        serviceParamDict["status"]  =   ESS_PUBLISHED
        self.db.insert("taxiservice",serviceParamDict)
        
        condition={"phone=":serviceParamDict["phone"],"departureTime=":serviceParamDict["departureTime"]}
        result = self.db.fetchall("taxiservice",condition)
        if result:
            pubID = result[-1][0]
            buf2 = "MC2CSP/1.0 PUBLISH 200 OK\r\n"
            buf2 += getDefaultTime()
            buf2 += sessionStr + "\r\n"
            buf2 += "PubID: %d\r\n"%pubID
            buf2 += cseqStr + "\r\n"
        else:
            raise Exception,"somehow,the condition can not get the latest inserted result"

        #serviceParamDict["pubID"] = pubID
        #self.log.debug("%s"%serviceParamDict)
        #self.session.notifyRequest("PUBLISH",(serviceParamDict,seriveParamList,locationParams))
        self.session.sendData(buf2 + TERMINATOR)

class UNPUBLISHRequester(Requester):

    def __init__(self,session,responseTimeout):
                                                #this indicates the msg center
       super(UNPUBLISHRequester,self).__init__(session,responseTimeout,"UNPUBLISHRequester")


class UNPUBLISHResponser(object):
    """
        currently, just delete the service
    """

    def __init__(self,session):
        self.session = session
        self.log  = session.log
        self.db    = database.CreateDB(session)

    def handle(self,buf):

        strlist = buf.splitlines()

        locationParams={}
        for line1 in strlist:
            #line1 = line.lstrip()
            if line1.startswith("PubID:"):
                    pubID = getPubID(line1)
                    
            elif line1.startswith("CSeq:"):
                    cseqStr = line1

            elif line1.startswith("Session:"):
                    sessionStr = line1
            elif line1.startswith("departureTime:"):
                    departureTime = getTime(getItem(line1)[1])     
            else:
                    parseLocationParams(locationParams,line1)

        condition={"pubID":pubID}
        self.db.delete("taxiservice",condition)
        #database.updateLocation(self.db,"location",locationParams)

        buf2 = "MC2CSP/1.0 UNPUBLISH 200 OK\r\n"
        buf2 += getDefaultTime()
        buf2 += sessionStr + "\r\n"
        buf2 += cseqStr + "\r\n"

        self.session.sendData(buf2 + TERMINATOR)
        idx = configall.getTimeIdx(departureTime)
        configall.matchEngine.deleteRequest(idx,pubID)
        
class LOGOUTRequester(Requester):

    def __init__(self,session,responseTimeout):
                                                #this indicates the msg center
       super(LOGOUTRequester,self).__init__(session,responseTimeout,"LOGOUTRequester")

         
class LOGOUTResponser(object):
    """
        handle logout request
    """
    

    def __init__(self,session):
        self.session = session
        self.log  = session.log
        self.db    = database.CreateDB(session)

    def handle(self,buf):

        strlist = buf.splitlines()

        for line in strlist:
            line1 = line.lstrip()
            if line1.startswith("From:"):

                    key,phone = getItem(line1)

            elif line1.startswith("CSeq:"):
                    cseqStr = line1

            elif line1.startswith("Session:"):
                    sessionStr = line1

        buf2 = "MC2CSP/1.0 LOGOUT 200 OK\r\n"
        buf2 += getDefaultTime()
        buf2 += sessionStr + "\r\n"
        buf2 += cseqStr + "\r\n"
        #for logout, let's send the response then exit the session
        
        self.session.sendData(buf2)
        self.session.handle_close()
      
class NOTIFYRequester(Requester):

    """
    Handle the notify response, only the gps info is needed so far
    """
    def __init__(self,session,responseTimeout):
                                                #this indicates the msg center
       super(NOTIFYRequester,self).__init__(session,responseTimeout,"NOTIFYRequester")

    def handle(self,buf):
        retCode,retInfo = getTheRetInfo(buf)
        strlist = buf.splitlines()
        gpsInfo =""
        for line in strlist:
            line1 = line.lstrip()
            if line1.startswith("CSeq:"):
                    cseq = getCSeq(line1)
            elif line1.startswith("Action:"):
                 key,action = getItem(line1)
                 self.extraInfo[key] = action
            elif line1.startswith("Location:") or line1.startswith("Time:"):
                 gpsInfo += line1 + "\r\n"
            elif line1.startswith(CSTR2_PUBID):
                 self.extraInfo[CSTR2_PUBID] = int(getItem(line1)[1])
                 
        self.extraInfo[CSTR2_GPS] = gpsInfo
        self.session.notifyResponse(cseq,retCode,retInfo,self.extraInfo)
        
def parseComboudCA(serviceParamDict,strlist):
    subIDList=[]
    for idx,line in enumerate(strlist):
        if line.startswith("pubID:"):
            subIDList.append(idx)
    num = len(subIDList)
    mainList = strlist[:subIDList[1]]
    parseServiceParams(serviceParamDict,mainList)
    groupList=[]
    for idx,subID in enumerate(subIDList):
        subDict={}
        subList=None
        if idx==num-1:#last one
            subList = strlist[subIDList[idx]:]
            
        elif idx>0:
            subList = strlist[subIDList[idx]:subIDList[idx+1]]
        if subList:
            parseServiceParams(subDict,subList) 
            groupList.append((subDict,subList))
    serviceParamDict[CSTR3_POOLINGGROUP]=groupList
    strlist =  mainList #the mainlist will be returned  
class NOTIFYResponser(object):
    """
        This is the most important handler to process the action which is a subMethod of
        NOTIFY.

    """

    def __init__(self,session):

        self.session = session
        self.log  = session.log
        
    def handle(self,buf):
        """
        extract the important infomation of the request.
        1, the serviceParam if have, which will offer the dict and list both
        2, the location paramms for possible use by the owner
        3, the mandtory fields for standby response
        
        most actions need further process by the owner, so the response will stand by until the process done.
        The final response is sent by L{StandbyTask}.
        """
        strlist = buf.splitlines()
        num = 0
        serviceParamDict={}
        seriveParamList=[]
        locationParams={}
        mandtoryFields=""
        for line in strlist:
            num += 1
            line1 = line.lstrip()
            if line1.startswith("Action:"):
                 mandtoryFields += line1 +"\r\n"
                 action = getItem(line1)[1]
                
                 seriveParamList = strlist[num:]
                 if action==CSTR_CA and buf.find(CSTR3_POOLINGIDGROUP)>0:
                     parseComboudCA(serviceParamDict,seriveParamList)
                 else:
                     parseServiceParams(serviceParamDict,seriveParamList)

                 if serviceParamDict.has_key("pubID"):
                     mandtoryFields+= "pubID: %d\r\n"%serviceParamDict["pubID"]
                 self.session.notifyRequest("NOTIFY",(action,serviceParamDict,seriveParamList,locationParams,mandtoryFields))
                 break

            elif line1.startswith("CSeq:"):

                 cseqStr = line1
                 cseq = getCSeq(line1)
                 mandtoryFields += line1+"\r\n"

            elif line1.startswith("Session:"):
                 sessionStr = line1
                 mandtoryFields += line1+"\r\n"
            else:
                 parseLocationParams(locationParams,line1)
                 

if __name__=="__main__":

      dict1={"sdf":1,"xcv":2}
      for key,value in dict1.items():
          print key


